A walkthrough of Ernest (2005)’s original analytical approach, from close reading of the paper.

Questions

  1. Is energy use across body size categories (regardless of species) uniform or multimodal?
  1. If energy use is not uniform across body size categories, does the species level body size distribution correspond to modes of energy use?

Data

Ernest data

Ernest drew data from the Andrews LTER, the Sevilleta, Niwot Ridge, and Portal.

The data available online do not quite match the descriptive statistics reported in Ernest (2005).

Translation to replicate-becs

Download raw data. By default data will be stored in subdirectories of replicate-becs/data/paper/raw/ for each site.

download_raw_paper_data()

Process raw data into the appropriate format. This is a data table with a record for each individual and columns for species and weight in grams. By default these tables will be stored in subdirectores of replicate-becs/data/paper/processed.

process_raw_data()
Loading in data version 1.106.0
[1] TRUE

Load data tables for each community. There should be 9 communities.

communities <- load_paper_data()
length(communities)
[1] 9

Each community should be a data table with columns for species and size for each individual, for example:

names(communities)
[1] "andrews"      "niwot"        "portal"       "sev-5pgrass"  "sev-5plarrea"
[6] "sev-goatdraw" "sev-rsgrass"  "sev-rslarrea" "sev-two22"   
head(communities[[1]])

Constructing distributions/metrics

Body size-energy use distributions (BSED)

Ernest method

  • Per individual, calculate metabolic rate as metabolic rate \(B \propto M^\frac{3}{4}\) where \(M\) is mass in grams.
  • Sum energy use of all individuals in body size classes of .2 natural log units.
    • Also try classes of .1 and .3 natural log units
  • Convert raw energy use values for each body size class into the proportion of all the energy used in that community used by that body size class. This allows for comparisons between communities.

Translation to replicate-becs

For every individual, calculate metabolic rate and assign to a size class.

communities_energy <- lapply(communities, FUN = make_community_table, ln_units = 0.2)
head(communities_energy[[1]])

For each community, sum total energy use for each size class, and convert to the proportion of total energy use for that community.

bseds <- lapply(communities_energy, FUN = make_bsed)
head(bseds[[1]])

Species-level body size distributions (BSD)

Ernest method

  • Frequency distributions of mean mass of each species in a community.
  • For plotting (but not statistics), smoothed using kernel density estimation.
    • Gaussian kernel to mimic the actual body size distribution in log space
    • avg. std dev of the mean of the logged masses = smoothing parameter \(h\)
    • align sampling points with the midpoint of each size class in the BSED
    • after Manly 1996, “Are there clumps in body-size distributions?”, Ecology

Translation to replicate-becs

Calculate mean mass of each species in each community.

bsds <- lapply(communities, FUN = make_bsd) 
head(bsds[[1]])

Energetic dominance (\(D_E\))

  • Define “energy use modes” as contiguous body size classes where the energy use of each size class > 5% of the community total.
    • i.e. a little bit more than the expectation if energy use is uniform across all body sizes
    • RMD is unsure of this. Doesn’t the uniform expectation depend on the number of size classes?
  • Calculate the total energy use for each species in the mode.
  • Calculate the “dominance” of the species with the highest energy use in that mode as \(D_E = p_{max}\), where \(p_max\) is the maximum proportion of energy use by any one species in a mode.
    • “a modification of the Berger-Parker dominance index (Berger and Parker 1970)”

Translation to replicate-becs

  • Find contiguous size classes where each class has >5% of total energy use
  • Calculate the total energy use for each species, and the proportion held by the species with the highest energy use (\(p_{max}\))
  • Return \(p_{max}\) for every mode, along with the min and max size classes in that mode for each community
energetic_dom <- lapply(communities_energy, FUN = energetic_dominance) 
head(energetic_dom[[1]])
  • To plot, combine all modes from all communities and plot a histogram of \(D_E\) values.

  • Out of curiousity, what happens if we define the modes with the cutoff proportional to the number of size classes (instead of a fixed 5%?)
energetic_dom_prop <- lapply(communities_energy, FUN = energetic_dominance, mode_cutoff = 'prop') 

  • RMD: They’re similar.

Statistical tests

Comparing BSEDs to uniform

Ernest approach

  • Use bootstrap sampling to compare to uniform distributions.
  • For every community, draw 10000 samples (sim communities):
    • Same number of individuals as the empirical community, drawn from a uniform distribution ranging from the smallest to largest body size individual metabolic rate of any individual in that community.
  • For sim communities and the empirical community, calculate a distribution overlap index (\(DOI\)):
    • \(DOI = \sum_k {|y_{ak} - y_{bk}|}\) where \(y\) is the value for size class \(k\) in communities \(a\) and \(b\).
    • \(DOI\) values will range from 0 (complete overlap) to 2 (no overlap).
    • For the BSED bootstraps, community \(a\) is the empirical or sim distribution, and community \(b\) is a true uniform distribution (i.e. \(y_{bk} = \frac{1}{\max(k)}\) for all \(k\))
      • “True uniform distribution”: There are exactly the same number of individuals of every size.
  • Calculate the \(DOI\) for all sim communities and the empirical.
  • Find the quantile value for the empirical \(DOI\) compared to the distribution of sim \(DOI\)s. This is the p-value; i.e. the proportion of sim uniform distributions with DOIs greater than the empirical.

Translation to replicate-becs

  • For a given empirical community, draw 10000 sim communities each with the same number of individuals \(n\), with body sizes randomly drawn from a uniform distribution from the minimum to maximum body size in that community.
  • Calculate the \(DOI\) of each sim community compared to a true uniform distribution.
    • True uniform distribution = every size from the minimum to the maximum size in the community (by .1g) has exactly one individual.
bsed_uniform_bootstraps <- lapply(communities, FUN = community_bootstrap,  bootstrap_function = 'bootstrap_unif_bsed_doi', nbootstraps = 10000)

See issue #4 on github.

Compare BSEDs among communities

Ernest approach

  • For every pair of communities, create a pool of masses of all individuals from both communities.
  • Draw two new communities with the same number of individuals as the empirical communities, pulling masses at random from the pool, with replacement.
  • Calculate the DOI for the BSEDs of the two sample communities.
  • Repeat 10000 for each pair.
  • The P value is the proportion of sample DOIs greater (i.e. less overlap) than the empirical value.

Translation to replicate-becs

  • For every pair of communities, pool all the masses
  • Resample two communities of the right sizes
  • Construct BSEDs for both communities
  • Calculate the DOI of the two BSEDs
  • Repeat 10000x
community_combination_indices = utils::combn(x = c(1:9), m = 2, simplify = TRUE) %>%
  t() %>%
  as.data.frame() %>%
  dplyr::rename(community_a = V1, community_b = V2)
combine_communities = function(indices, communities) {
  community_combination = list(community_a = communities[[indices[1]]], community_b = communities[[indices[2]]], community_names = c(names(communities)[[indices[1]]], names(communities)[[indices[2]]]))
  
  return(community_combination)
}
community_combinations = apply(community_combination_indices, MARGIN = 1, FUN = combine_communities, communities = communities)
bsed_crosscomm_bootstraps = lapply(community_combinations, FUN = community_bootstrap, 
                                   bootstrap_function = 'bootstrap_crosscomm_bseds', nbootstraps = 10000)

See histogram of p values for comparisons to see if commuities’ BSEDs are the same or different.

LS0tCnRpdGxlOiAiTmFycmF0aXZlIG9mIG9yaWdpbmFsIGFuYWx5c2lzIgphdXRob3I6ICJSZW5hdGEgRGlheiIKZGF0ZTogIjUvMTQvMjAxOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQpsaWJyYXJ5KHJlcGxpY2F0ZWJlY3MpCmRvd25sb2FkX2RhdGEgPSBGQUxTRQpgYGAKCkEgd2Fsa3Rocm91Z2ggb2YgRXJuZXN0ICgyMDA1KSdzIG9yaWdpbmFsIGFuYWx5dGljYWwgYXBwcm9hY2gsIGZyb20gY2xvc2UgcmVhZGluZyBvZiB0aGUgcGFwZXIuIAoKIyMgUXVlc3Rpb25zCgoxLiBJcyBlbmVyZ3kgdXNlIGFjcm9zcyBib2R5IHNpemUgY2F0ZWdvcmllcyAocmVnYXJkbGVzcyBvZiBzcGVjaWVzKSB1bmlmb3JtIG9yIG11bHRpbW9kYWw/CiAgLSB1bmlmb3JtIHdvdWxkIGNvcnJlc3BvbmQgZ2VuZXJhbGx5IHRvIGVuZXJnZXRpYyBlcXVpdmFsZW5jZS9EYW11dGgncyBydWxlLgogIC0gbXVsdGltb2RhbCBtaWdodCBzdWdnZXN0IGRpZmZlcmVudCByZXNvdXJjZSBhdmFpbGFiaWxpdHkgZm9yIGRpZmZlcmVudCBib2R5IHNpemVzLgoyLiBJZiBlbmVyZ3kgdXNlIGlzIG5vdCB1bmlmb3JtIGFjcm9zcyBib2R5IHNpemUgY2F0ZWdvcmllcywgZG9lcyB0aGUgc3BlY2llcyBsZXZlbCBib2R5IHNpemUgZGlzdHJpYnV0aW9uIGNvcnJlc3BvbmQgdG8gbW9kZXMgb2YgZW5lcmd5IHVzZT8KICAtIGkuZS4gYXJlIHRoZXJlIG1vcmUgc3BlY2llcyB3aXRoIG1lYW4gYm9keSBzaXplcyBhcm91bmQgdGhlIG1vZGVzIG9mIHRoZSBib2R5IHNpemUtZW5lcmd5IHVzZSBkaXN0cmlidXRpb24/CiAgLSBpZiBzbywgbWF5YmUgaXQncyBnb29kIHRvIGJlIGNlcnRhaW4gc2l6ZXMsIGFuZCBzcGVjaWVzIGFjY3VtdWxhdGUgYXQgdGhvc2Ugb3B0aW1hLgoKCiMjIERhdGEKCiMjIyMgRXJuZXN0IGRhdGEKRXJuZXN0IGRyZXcgZGF0YSBmcm9tIHRoZSBBbmRyZXdzIExURVIsIHRoZSBTZXZpbGxldGEsIE5pd290IFJpZGdlLCBhbmQgUG9ydGFsLiAKClRoZSBkYXRhIGF2YWlsYWJsZSBvbmxpbmUgZG8gbm90IHF1aXRlIG1hdGNoIHRoZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHJlcG9ydGVkIGluIEVybmVzdCAoMjAwNSkuIAoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgpEb3dubG9hZCByYXcgZGF0YS4gQnkgZGVmYXVsdCBkYXRhIHdpbGwgYmUgc3RvcmVkIGluIHN1YmRpcmVjdG9yaWVzIG9mIGByZXBsaWNhdGUtYmVjcy9kYXRhL3BhcGVyL3Jhdy9gIGZvciBlYWNoIHNpdGUuIApgYGB7ciBkb3dubG9hZCBkYXRhIGlmIG5vdCBkb3dubG9hZGVkLCBpbmNsdWRlID0gRn0KaWYoZG93bmxvYWRfZGF0YSkgZG93bmxvYWRfcmF3X3BhcGVyX2RhdGEoKQpgYGAKCmBgYHtyIGRvd25sb2FkIHJhdyBkYXRhLCBldmFsID0gRn0KZG93bmxvYWRfcmF3X3BhcGVyX2RhdGEoKQpgYGAKClByb2Nlc3MgcmF3IGRhdGEgaW50byB0aGUgYXBwcm9wcmlhdGUgZm9ybWF0LiBUaGlzIGlzIGEgZGF0YSB0YWJsZSB3aXRoIGEgcmVjb3JkIGZvciBlYWNoIGluZGl2aWR1YWwgYW5kIGNvbHVtbnMgZm9yIGBzcGVjaWVzYCBhbmQgYHdlaWdodGAgaW4gZ3JhbXMuIEJ5IGRlZmF1bHQgdGhlc2UgdGFibGVzIHdpbGwgYmUgc3RvcmVkIGluIHN1YmRpcmVjdG9yZXMgb2YgYHJlcGxpY2F0ZS1iZWNzL2RhdGEvcGFwZXIvcHJvY2Vzc2VkYC4gCgpgYGB7ciBwcm9jZXNzIHBhcGVyIGRhdGF9CnByb2Nlc3NfcmF3X2RhdGEoKQpgYGAKCkxvYWQgZGF0YSB0YWJsZXMgZm9yIGVhY2ggY29tbXVuaXR5LiBUaGVyZSBzaG91bGQgYmUgOSBjb21tdW5pdGllcy4KCmBgYHtyIGxvYWQgY29tbXVuaXR5IGRhdGEsIGVjaG89VFJVRX0KY29tbXVuaXRpZXMgPC0gbG9hZF9wYXBlcl9kYXRhKCkKCmxlbmd0aChjb21tdW5pdGllcykKYGBgCgpFYWNoIGNvbW11bml0eSBzaG91bGQgYmUgYSBkYXRhIHRhYmxlIHdpdGggY29sdW1ucyBmb3Igc3BlY2llcyBhbmQgc2l6ZSBmb3IgZWFjaCBpbmRpdmlkdWFsLCBmb3IgZXhhbXBsZToKCmBgYHtyIGluc3BlY3QgY29tbXVuaXR5IGRhdGF9Cm5hbWVzKGNvbW11bml0aWVzKQpoZWFkKGNvbW11bml0aWVzW1sxXV0pCmBgYAoKCiMjIENvbnN0cnVjdGluZyBkaXN0cmlidXRpb25zL21ldHJpY3MKCiMjIyBCb2R5IHNpemUtZW5lcmd5IHVzZSBkaXN0cmlidXRpb25zIChCU0VEKQoKIyMjIyBFcm5lc3QgbWV0aG9kCgotIFBlciBpbmRpdmlkdWFsLCBjYWxjdWxhdGUgbWV0YWJvbGljIHJhdGUgYXMgbWV0YWJvbGljIHJhdGUgJEIgXHByb3B0byBNXlxmcmFjezN9ezR9JCB3aGVyZSAkTSQgaXMgbWFzcyBpbiBncmFtcy4KLSBTdW0gZW5lcmd5IHVzZSBvZiBhbGwgaW5kaXZpZHVhbHMgaW4gYm9keSBzaXplIGNsYXNzZXMgb2YgLjIgbmF0dXJhbCBsb2cgdW5pdHMuCiAgICAtIEFsc28gdHJ5IGNsYXNzZXMgb2YgLjEgYW5kIC4zIG5hdHVyYWwgbG9nIHVuaXRzCi0gQ29udmVydCByYXcgZW5lcmd5IHVzZSB2YWx1ZXMgZm9yIGVhY2ggYm9keSBzaXplIGNsYXNzIGludG8gdGhlIHByb3BvcnRpb24gb2YgYWxsIHRoZSBlbmVyZ3kgdXNlZCBpbiB0aGF0IGNvbW11bml0eSB1c2VkIGJ5IHRoYXQgYm9keSBzaXplIGNsYXNzLiBUaGlzIGFsbG93cyBmb3IgY29tcGFyaXNvbnMgYmV0d2VlbiBjb21tdW5pdGllcy4KCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKRm9yIGV2ZXJ5IGluZGl2aWR1YWwsIGNhbGN1bGF0ZSBtZXRhYm9saWMgcmF0ZSBhbmQgYXNzaWduIHRvIGEgc2l6ZSBjbGFzcy4gCgpgYGB7ciBjb25zdHJ1Y3QgQlNFRHN9CmNvbW11bml0aWVzX2VuZXJneSA8LSBsYXBwbHkoY29tbXVuaXRpZXMsIEZVTiA9IG1ha2VfY29tbXVuaXR5X3RhYmxlLCBsbl91bml0cyA9IDAuMikKCmhlYWQoY29tbXVuaXRpZXNfZW5lcmd5W1sxXV0pCmBgYAoKRm9yIGVhY2ggY29tbXVuaXR5LCBzdW0gdG90YWwgZW5lcmd5IHVzZSBmb3IgZWFjaCBzaXplIGNsYXNzLCBhbmQgY29udmVydCB0byB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCBlbmVyZ3kgdXNlIGZvciB0aGF0IGNvbW11bml0eS4KCmBgYHtyIG1ha2UgYnNlZHN9CmJzZWRzIDwtIGxhcHBseShjb21tdW5pdGllc19lbmVyZ3ksIEZVTiA9IG1ha2VfYnNlZCkKCmhlYWQoYnNlZHNbWzFdXSkKYGBgCgpgYGB7ciBwbG90IGJzZWRzLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9Cgpic2Vkc19wbG90IDwtIHBsb3RfcGFwZXJfZGlzdHMoYnNlZHMsIGRpc3RfdHlwZSA9ICdic2VkJykKCmludmlzaWJsZShic2Vkc19wbG90KQpgYGAKCiMjIyBTcGVjaWVzLWxldmVsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb25zIChCU0QpCgojIyMjIEVybmVzdCBtZXRob2QKLSBGcmVxdWVuY3kgZGlzdHJpYnV0aW9ucyBvZiBtZWFuIG1hc3Mgb2YgZWFjaCBzcGVjaWVzIGluIGEgY29tbXVuaXR5LgotIEZvciBwbG90dGluZyAoYnV0IG5vdCBzdGF0aXN0aWNzKSwgc21vb3RoZWQgdXNpbmcga2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbi4gCiAgICAtIEdhdXNzaWFuIGtlcm5lbCB0byBtaW1pYyB0aGUgYWN0dWFsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb24gaW4gbG9nIHNwYWNlCiAgICAtIGF2Zy4gc3RkIGRldiBvZiB0aGUgbWVhbiBvZiB0aGUgbG9nZ2VkIG1hc3NlcyA9IHNtb290aGluZyBwYXJhbWV0ZXIgJGgkCiAgICAtIGFsaWduIHNhbXBsaW5nIHBvaW50cyB3aXRoIHRoZSBtaWRwb2ludCBvZiBlYWNoIHNpemUgY2xhc3MgaW4gdGhlIEJTRUQKICAgIC0gYWZ0ZXIgTWFubHkgMTk5NiwgIkFyZSB0aGVyZSBjbHVtcHMgaW4gYm9keS1zaXplIGRpc3RyaWJ1dGlvbnM/IiwgX0Vjb2xvZ3lfCiAgICAKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgpDYWxjdWxhdGUgbWVhbiBtYXNzIG9mIGVhY2ggc3BlY2llcyBpbiBlYWNoIGNvbW11bml0eS4gCgpgYGB7ciBjb25zdHJ1Y3QgYnNkc30gCgpic2RzIDwtIGxhcHBseShjb21tdW5pdGllcywgRlVOID0gbWFrZV9ic2QpIAoKaGVhZChic2RzW1sxXV0pCmBgYAoKYGBge3IgcGxvdCBic2RzLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9Cgpic2RzX3Bsb3QgPC0gcGxvdF9wYXBlcl9kaXN0cyhic2RzLCBkaXN0X3R5cGUgPSAnYnNkJykKCmludmlzaWJsZShic2RzX3Bsb3QpCmBgYAoKCiMjIyBFbmVyZ2V0aWMgZG9taW5hbmNlICgkRF9FJCkKCi0gRGVmaW5lICJlbmVyZ3kgdXNlIG1vZGVzIiBhcyBjb250aWd1b3VzIGJvZHkgc2l6ZSBjbGFzc2VzIHdoZXJlIHRoZSBlbmVyZ3kgdXNlIG9mIGVhY2ggc2l6ZSBjbGFzcyA+IDUlIG9mIHRoZSBjb21tdW5pdHkgdG90YWwuIAogICAgLSBpLmUuIGEgbGl0dGxlIGJpdCBtb3JlIHRoYW4gdGhlIGV4cGVjdGF0aW9uIGlmIGVuZXJneSB1c2UgaXMgdW5pZm9ybSBhY3Jvc3MgYWxsIGJvZHkgc2l6ZXMKICAgIC0gUk1EIGlzIHVuc3VyZSBvZiB0aGlzLiBEb2Vzbid0IHRoZSB1bmlmb3JtIGV4cGVjdGF0aW9uIGRlcGVuZCBvbiB0aGUgbnVtYmVyIG9mIHNpemUgY2xhc3Nlcz8KLSBDYWxjdWxhdGUgdGhlIHRvdGFsIGVuZXJneSB1c2UgZm9yIGVhY2ggc3BlY2llcyBpbiB0aGUgbW9kZS4gCi0gQ2FsY3VsYXRlIHRoZSAiZG9taW5hbmNlIiBvZiB0aGUgc3BlY2llcyB3aXRoIHRoZSBoaWdoZXN0IGVuZXJneSB1c2UgaW4gdGhhdCBtb2RlIGFzICREX0UgPSBwX3ttYXh9JCwgd2hlcmUgJHBfbWF4JCBpcyB0aGUgbWF4aW11bSBwcm9wb3J0aW9uIG9mIGVuZXJneSB1c2UgYnkgYW55IG9uZSBzcGVjaWVzIGluIGEgbW9kZS4gCiAgICAtICJhIG1vZGlmaWNhdGlvbiBvZiB0aGUgQmVyZ2VyLVBhcmtlciBkb21pbmFuY2UgaW5kZXggKEJlcmdlciBhbmQgUGFya2VyIDE5NzApIgoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCgotIEZpbmQgY29udGlndW91cyBzaXplIGNsYXNzZXMgd2hlcmUgZWFjaCBjbGFzcyBoYXMgPjUlIG9mIHRvdGFsIGVuZXJneSB1c2UKLSBDYWxjdWxhdGUgdGhlIHRvdGFsIGVuZXJneSB1c2UgZm9yIGVhY2ggc3BlY2llcywgYW5kIHRoZSBwcm9wb3J0aW9uIGhlbGQgYnkgdGhlIHNwZWNpZXMgd2l0aCB0aGUgaGlnaGVzdCBlbmVyZ3kgdXNlICgkcF97bWF4fSQpCi0gUmV0dXJuICRwX3ttYXh9JCBmb3IgZXZlcnkgbW9kZSwgYWxvbmcgd2l0aCB0aGUgbWluIGFuZCBtYXggc2l6ZSBjbGFzc2VzIGluIHRoYXQgbW9kZSBmb3IgZWFjaCBjb21tdW5pdHkKCmBgYHtyIGVuZXJnZXRpYyBkb21pbmFuY2V9CgplbmVyZ2V0aWNfZG9tIDwtIGxhcHBseShjb21tdW5pdGllc19lbmVyZ3ksIEZVTiA9IGVuZXJnZXRpY19kb21pbmFuY2UpIAoKaGVhZChlbmVyZ2V0aWNfZG9tW1sxXV0pCgpgYGAKCi0gVG8gcGxvdCwgY29tYmluZSBhbGwgbW9kZXMgZnJvbSBhbGwgY29tbXVuaXRpZXMgYW5kIHBsb3QgYSBoaXN0b2dyYW0gb2YgJERfRSQgdmFsdWVzLgoKYGBge3IgcGxvdCBFZCwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9NX0KZV9kb21fcGxvdCA8LSBwbG90X2VfZG9tKGVuZXJnZXRpY19kb20pCmVfZG9tX3Bsb3QKYGBgCgoKLSBPdXQgb2YgY3VyaW91c2l0eSwgd2hhdCBoYXBwZW5zIGlmIHdlIGRlZmluZSB0aGUgbW9kZXMgd2l0aCB0aGUgY3V0b2ZmIHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyIG9mIHNpemUgY2xhc3NlcyAoaW5zdGVhZCBvZiBhIGZpeGVkIDUlPykKCmBgYHtyIGVkb20gcHJvcG9ydGlvbmFsfQplbmVyZ2V0aWNfZG9tX3Byb3AgPC0gbGFwcGx5KGNvbW11bml0aWVzX2VuZXJneSwgRlVOID0gZW5lcmdldGljX2RvbWluYW5jZSwgbW9kZV9jdXRvZmYgPSAncHJvcCcpIApgYGAKCmBgYHtyIHBsb3QgZWRvbSBwcm9wb3J0aW9uYWwsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CmVfZG9tX3Byb3BfcGxvdCA8LSBwbG90X2VfZG9tKGVuZXJnZXRpY19kb21fcHJvcCkKZV9kb21fcHJvcF9wbG90CmBgYAoKLSBSTUQ6IFRoZXkncmUgc2ltaWxhci4gCgojIyBTdGF0aXN0aWNhbCB0ZXN0cwoKIyMjIENvbXBhcmluZyBCU0VEcyB0byB1bmlmb3JtCgojIyMjIEVybmVzdCBhcHByb2FjaAoKLSBVc2UgYm9vdHN0cmFwIHNhbXBsaW5nIHRvIGNvbXBhcmUgdG8gdW5pZm9ybSBkaXN0cmlidXRpb25zLgotIEZvciBldmVyeSBjb21tdW5pdHksIGRyYXcgMTAwMDAgc2FtcGxlcyAoc2ltIGNvbW11bml0aWVzKToKICAgIC0gU2FtZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgYXMgdGhlIGVtcGlyaWNhbCBjb21tdW5pdHksIGRyYXduIGZyb20gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiByYW5naW5nIGZyb20gdGhlIHNtYWxsZXN0IHRvIGxhcmdlc3Qgfn5ib2R5IHNpemV+fiBpbmRpdmlkdWFsIG1ldGFib2xpYyByYXRlIG9mIGFueSBpbmRpdmlkdWFsIGluIHRoYXQgY29tbXVuaXR5LgotIEZvciBzaW0gY29tbXVuaXRpZXMgYW5kIHRoZSBlbXBpcmljYWwgY29tbXVuaXR5LCBjYWxjdWxhdGUgYSBkaXN0cmlidXRpb24gb3ZlcmxhcCBpbmRleCAoJERPSSQpOgogICAgLSAkRE9JID0gXHN1bV9rIHt8eV97YWt9IC0geV97Ymt9fH0kIHdoZXJlICR5JCBpcyB0aGUgdmFsdWUgZm9yIHNpemUgY2xhc3MgJGskIGluIGNvbW11bml0aWVzICRhJCBhbmQgJGIkLgogICAgLSAkRE9JJCB2YWx1ZXMgd2lsbCByYW5nZSBmcm9tIDAgKGNvbXBsZXRlIG92ZXJsYXApIHRvIDIgKG5vIG92ZXJsYXApLiAKICAgIC0gRm9yIHRoZSBCU0VEIGJvb3RzdHJhcHMsIGNvbW11bml0eSAkYSQgaXMgdGhlIGVtcGlyaWNhbCBvciBzaW0gZGlzdHJpYnV0aW9uLCBhbmQgY29tbXVuaXR5ICRiJCBpcyBhIHRydWUgdW5pZm9ybSBkaXN0cmlidXRpb24gfn4oaS5lLiAkeV97Ymt9ID0gXGZyYWN7MX17XG1heChrKX0kIGZvciBhbGwgJGskKX5+CiAgICAgICAgLSAiVHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiI6IFRoZXJlIGFyZSBleGFjdGx5IHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBvZiBldmVyeSBzaXplLiAKLSBDYWxjdWxhdGUgdGhlICRET0kkIGZvciBhbGwgc2ltIGNvbW11bml0aWVzIGFuZCB0aGUgZW1waXJpY2FsLgotIEZpbmQgdGhlIHF1YW50aWxlIHZhbHVlIGZvciB0aGUgZW1waXJpY2FsICRET0kkIGNvbXBhcmVkIHRvIHRoZSBkaXN0cmlidXRpb24gb2Ygc2ltICRET0kkcy4gVGhpcyBpcyB0aGUgcC12YWx1ZTsgaS5lLiB0aGUgcHJvcG9ydGlvbiBvZiBzaW0gdW5pZm9ybSBkaXN0cmlidXRpb25zIHdpdGggRE9JcyBncmVhdGVyIHRoYW4gdGhlIGVtcGlyaWNhbC4KCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKLSBGb3IgYSBnaXZlbiBlbXBpcmljYWwgY29tbXVuaXR5LCBkcmF3IDEwMDAwIHNpbSBjb21tdW5pdGllcyBlYWNoIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIGluZGl2aWR1YWxzICRuJCwgd2l0aCBib2R5IHNpemVzIHJhbmRvbWx5IGRyYXduIGZyb20gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBmcm9tIHRoZSBtaW5pbXVtIHRvIG1heGltdW0gYm9keSBzaXplIGluIHRoYXQgY29tbXVuaXR5LgotIENhbGN1bGF0ZSB0aGUgJERPSSQgb2YgZWFjaCBzaW0gY29tbXVuaXR5IGNvbXBhcmVkIHRvIGEgdHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbi4gCiAgICAtIFRydWUgdW5pZm9ybSBkaXN0cmlidXRpb24gPSBldmVyeSBzaXplIGZyb20gdGhlIG1pbmltdW0gdG8gdGhlIG1heGltdW0gc2l6ZSBpbiB0aGUgY29tbXVuaXR5IChieSAuMWcpIGhhcyBleGFjdGx5IG9uZSBpbmRpdmlkdWFsLgoKYGBge3IgQlNFRC11bmlmb3JtIGJvb3RzdHJhcHBlZCBET0lzfQoKYnNlZF91bmlmb3JtX2Jvb3RzdHJhcHMgPC0gbGFwcGx5KGNvbW11bml0aWVzLCBGVU4gPSBjb21tdW5pdHlfYm9vdHN0cmFwLCAgYm9vdHN0cmFwX2Z1bmN0aW9uID0gJ2Jvb3RzdHJhcF91bmlmX2JzZWRfZG9pJywgbmJvb3RzdHJhcHMgPSAxMDAwMCkKCmBgYAoKCl9TZWUgaXNzdWUgIzQgb24gZ2l0aHViLl8KICAgIAogICAgCmBgYHtyIHBsb3QgQlNFRC11bmlmb3JtIGJvb3RzdHJhcCBET0lzIHYgZW1waXJpY2FsLGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0gCgpic2VkX3VuaWZvcm1fYm9vdHN0cmFwX3Bsb3QgPC0gcGxvdF9wYXBlcl9kaXN0cyhic2VkX3VuaWZvcm1fYm9vdHN0cmFwcywgZGlzdF90eXBlID0gJ2JzZWRfYm9vdHN0cmFwcycpCgppbnZpc2libGUoYnNlZF91bmlmb3JtX2Jvb3RzdHJhcF9wbG90KQpgYGAKCiMjIyBDb21wYXJlIEJTRURzIGFtb25nIGNvbW11bml0aWVzCgojIyMjIEVybmVzdCBhcHByb2FjaAotIEZvciBldmVyeSBwYWlyIG9mIGNvbW11bml0aWVzLCBjcmVhdGUgYSBwb29sIG9mIG1hc3NlcyBvZiBhbGwgaW5kaXZpZHVhbHMgZnJvbSBib3RoIGNvbW11bml0aWVzLgotIERyYXcgdHdvIG5ldyBjb21tdW5pdGllcyB3aXRoIHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBhcyB0aGUgZW1waXJpY2FsIGNvbW11bml0aWVzLCBwdWxsaW5nIG1hc3NlcyBhdCByYW5kb20gZnJvbSB0aGUgcG9vbCwgd2l0aCByZXBsYWNlbWVudC4KLSBDYWxjdWxhdGUgdGhlIERPSSBmb3IgdGhlIEJTRURzIG9mIHRoZSB0d28gc2FtcGxlIGNvbW11bml0aWVzLgotIFJlcGVhdCAxMDAwMCBmb3IgZWFjaCBwYWlyLgotIFRoZSBQIHZhbHVlIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHNhbXBsZSBET0lzIGdyZWF0ZXIgKGkuZS4gbGVzcyBvdmVybGFwKSB0aGFuIHRoZSBlbXBpcmljYWwgdmFsdWUuIAoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgCi0gRm9yIGV2ZXJ5IHBhaXIgb2YgY29tbXVuaXRpZXMsIHBvb2wgYWxsIHRoZSBtYXNzZXMKLSBSZXNhbXBsZSB0d28gY29tbXVuaXRpZXMgb2YgdGhlIHJpZ2h0IHNpemVzCi0gQ29uc3RydWN0IEJTRURzIGZvciBib3RoIGNvbW11bml0aWVzCi0gQ2FsY3VsYXRlIHRoZSBET0kgb2YgdGhlIHR3byBCU0VEcwotIFJlcGVhdCAxMDAwMHgKCmBgYHtyIHBhaXJzIGZvciBjcm9zc2NvbW11bml0eSBCU0VEIGNvbXBhcmlzb25zfQpjb21tdW5pdHlfY29tYmluYXRpb25faW5kaWNlcyA9IHV0aWxzOjpjb21ibih4ID0gYygxOjkpLCBtID0gMiwgc2ltcGxpZnkgPSBUUlVFKSAlPiUKICB0KCkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGRwbHlyOjpyZW5hbWUoY29tbXVuaXR5X2EgPSBWMSwgY29tbXVuaXR5X2IgPSBWMikKCmNvbWJpbmVfY29tbXVuaXRpZXMgPSBmdW5jdGlvbihpbmRpY2VzLCBjb21tdW5pdGllcykgewogIGNvbW11bml0eV9jb21iaW5hdGlvbiA9IGxpc3QoY29tbXVuaXR5X2EgPSBjb21tdW5pdGllc1tbaW5kaWNlc1sxXV1dLCBjb21tdW5pdHlfYiA9IGNvbW11bml0aWVzW1tpbmRpY2VzWzJdXV0sIGNvbW11bml0eV9uYW1lcyA9IGMobmFtZXMoY29tbXVuaXRpZXMpW1tpbmRpY2VzWzFdXV0sIG5hbWVzKGNvbW11bml0aWVzKVtbaW5kaWNlc1syXV1dKSkKICAKICByZXR1cm4oY29tbXVuaXR5X2NvbWJpbmF0aW9uKQp9Cgpjb21tdW5pdHlfY29tYmluYXRpb25zID0gYXBwbHkoY29tbXVuaXR5X2NvbWJpbmF0aW9uX2luZGljZXMsIE1BUkdJTiA9IDEsIEZVTiA9IGNvbWJpbmVfY29tbXVuaXRpZXMsIGNvbW11bml0aWVzID0gY29tbXVuaXRpZXMpCgpgYGAKCmBgYHtyIGNyb3NzIGNvbW11bml0eSBCU0VEIGNvbXBhcmlzb25zfQoKYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcyA9IGxhcHBseShjb21tdW5pdHlfY29tYmluYXRpb25zLCBGVU4gPSBjb21tdW5pdHlfYm9vdHN0cmFwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXBfZnVuY3Rpb24gPSAnYm9vdHN0cmFwX2Nyb3NzY29tbV9ic2VkcycsIG5ib290c3RyYXBzID0gMTAwMDApCgoKYGBgCgpgYGB7ciBwbG90IGNyb3NzIGNvbW11bml0eSBjb21wYXJpc29ucywgZWNobyA9IEYsIGZpZy5oZWlnaHQ9MzAsIGZpZy53aWR0aD0xMH0KCmNyb3NzY29tbV9ib290c3RyYXBfcGxvdCA9IHBsb3RfY3Jvc3Njb21tX2JzZWRzKGJzZWRfY3Jvc3Njb21tX2Jvb3RzdHJhcHMpCgppbnZpc2libGUoY3Jvc3Njb21tX2Jvb3RzdHJhcF9wbG90KQoKYGBgCgpgYGB7ciBwbG90IGNyb3NzIGNvbW11bml0eSBwIHZhbHVlcywgZWNobyA9IEYsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSA1fQpwdmFsc19oaXN0b2dyYW0gPSBwbG90X3B2YWxzKGJzZWRfY3Jvc3Njb21tX2Jvb3RzdHJhcHMpCgpwdmFsc19oaXN0b2dyYW0KYGBgCgoKU2VlIGhpc3RvZ3JhbSBvZiBwIHZhbHVlcyBmb3IgY29tcGFyaXNvbnMgdG8gc2VlIGlmIGNvbW11aXRpZXMnIEJTRURzIGFyZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQuCg==